﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using PluggableModulesInterface;
using System.Reflection;
using Settings;
using Utils;
using System.IO;
using StaticThreadManagement;
using System.Diagnostics;
using System.Threading;

namespace SMSROUTER
{
    public partial class FrmRouterList : Form
    {
        Dictionary<string, IPluggableModule> _ListOfModule;
        DataTable _tblModuleList;
        IEnumerable<PropertyInfo> _IPproperties;
        public struct ModuleStatus
        {
            public const string Stopped = "Stopped";
            public const string Running = "Running";
            public const string Unknown = "Unknown";
        }
        public struct ButtonAction
        {
            public const string Start = "Start";
            public const string Stop = "Stop";
        }

        public FrmRouterList()
        {
            InitializeComponent();
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            try
            {
                switch (keyData)
                {
                    case Keys.F2:
                        btnAddDll.PerformClick();
                        return base.ProcessCmdKey(ref msg, keyData);
                    case Keys.F4:
                        btnConfig.PerformClick();
                        return base.ProcessCmdKey(ref msg, keyData);
                    case Keys.F5:
                        btnRefresh.PerformClick();
                        return base.ProcessCmdKey(ref msg, keyData);
                    case Keys.Escape:
                        this.Close();
                        return base.ProcessCmdKey(ref msg, keyData);
                    default:
                        return base.ProcessCmdKey(ref msg, keyData);
                }
            }
            catch (Exception)
            {
                return base.ProcessCmdKey(ref msg, keyData);
            }
        }

        void SetBtnStartStopText(DataGridViewRow row)
        {
            if (_ListOfModule[row.Cells["DicKey"].Value.ToString()].Running)
            {
                btnStartStop.Text = ButtonAction.Stop;
            }
            else
            {
                btnStartStop.Text = ButtonAction.Start;
            }
        }

        void StartStopModule(DataGridViewRow row)
        {
            IPluggableModule item = _ListOfModule[row.Cells["DicKey"].Value.ToString()];
            if (item != null)
            {
                if (btnStartStop.Text == ButtonAction.Start)
                {
                    if (!item.Running)
                    {
                        item.Start();
                    }
                }
                else
                {
                    if (item.Running)
                    {
                        item.Stop();
                    }
                }
                row.Cells["Running"].Value = item.Running;
            }
        }

        void SetParentControl()
        {
            string action = "";
            bool moRunning = false, mtRunning = false;
            bool stopped = false;
            foreach (IPluggableModule item in _ListOfModule.Values)
            {
                if (item.Running)
                {
                    if (item.Type.StartsWith("MO", StringComparison.CurrentCultureIgnoreCase))
                        moRunning = true;
                    else mtRunning = true;
                }
                else stopped = true;
            }
            if ((moRunning || mtRunning) && stopped) action = ButtonAction.Stop;
            else if (moRunning || mtRunning) action = ButtonAction.Start;
            else action = ButtonAction.Stop;
            ((FrmMain)this.MdiParent).SetControl(action);

            // Star/Stop static threads
            if (moRunning || mtRunning)
            {
                if (moRunning && !StaticThreadManage.MORunning)
                {
                    StaticThreadManage.StartMO();
                }
                if (mtRunning && !StaticThreadManage.MTRunning)
                {
                    StaticThreadManage.StartMT();
                }
                if (!moRunning) StaticThreadManage.StopMO();
                if (!mtRunning) StaticThreadManage.StopMT();
                ((FrmMain)this.MdiParent).SetMenuConnectionEnable(false);
            }
            else
            {
                StaticThreadManage.StopAll();
                ((FrmMain)this.MdiParent).SetMenuConnectionEnable(true);
            }
        }

        public void LoadData()
        {
            try
            {
                FrmProgressBar.Show("Loading...");

                dgvModuleList.RowEnter -= new DataGridViewCellEventHandler(dgvModuleList_RowEnter);
                dgvModuleList.RowEnter += new DataGridViewCellEventHandler(dgvModuleList_RowEnter);
                dgvModuleList.DoubleClick -= new EventHandler(dgvModuleList_DoubleClick);
                dgvModuleList.DoubleClick += new EventHandler(dgvModuleList_DoubleClick);

                // Nạp lại các dll chưa hoạt động
                PluggableManage.LoadExistingModules(Settings.AppSetting.AppModulesPath);

                // Tạo cấu trúc của dataTable
                if (_tblModuleList != null) { _tblModuleList.Rows.Clear(); _tblModuleList.Columns.Clear(); }
                _tblModuleList = ObjectClass.CreateTableSchema(typeof(IPluggableModule));
                _tblModuleList.Columns.Add("DicKey", typeof(string));

                // Add các row cho dataTable
                _IPproperties = Utils.ObjectClass.GetProperties(typeof(IPluggableModule)).Where(p => p.CanRead);
                _ListOfModule = PluggableManage.GetListOfModule();
                foreach (var item in _ListOfModule)
                {
                    AddNewRow(item, _IPproperties);
                }

                dgvModuleList.DataSource = _tblModuleList;
                if (dgvModuleList.Columns["DicKey"] != null) dgvModuleList.Columns["DicKey"].Visible = false;
                dgvModuleList.AutoResizeColumns();

                ((FrmMain)this.MdiParent).SetMenuStartStopEnable();

                FrmProgressBar.Hide();
            }
            catch (Exception)
            {
                FrmProgressBar.Hide();
                throw;
            }
        }

        void AddNewRow(KeyValuePair<string, IPluggableModule> item, IEnumerable<PropertyInfo> properties)
        {
            if (item.Value != null && properties != null)
            {
                DataRow dr = _tblModuleList.NewRow();
                dr["DicKey"] = item.Key;
                foreach (var pi in properties)
                {
                    dr[pi.Name] = pi.GetValue(item.Value, null);
                }
                _tblModuleList.Rows.Add(dr);
            }
        }

        void CopyFile(string sourceFilePath, string desFilePath, bool overwrite)
        {
            if (desFilePath.EndsWith(".dll", StringComparison.CurrentCultureIgnoreCase))
            {
                if (PluggableManage.UnloadAssemblyOfStoppedModule(desFilePath))
                {
                    File.Copy(sourceFilePath, desFilePath, overwrite);
                }
            }
            else
            {
                File.Copy(sourceFilePath, desFilePath, overwrite);
            }
        }

        void dgvModuleList_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                if (dgvModuleList.SelectedRows.Count > 0)
                {
                    SetBtnStartStopText(dgvModuleList.SelectedRows[0]);
                }
                else if (dgvModuleList.RowCount > 0)
                {
                    SetBtnStartStopText(dgvModuleList.Rows[0]);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        void dgvModuleList_DoubleClick(object sender, EventArgs e)
        {
            btnConfig.PerformClick();
        }

        private void FrmRouterList_Load(object sender, EventArgs e)
        {
            try
            {
                LoadData();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void btnAddDll_Click(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog fd = new OpenFileDialog();
                fd.Title = "Chose your dll and config file";
                fd.Filter = "dll files (*.dll), config files (*.config)|*.dll;*.config";
                fd.Multiselect = true;
                if (fd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    string modulesPath = Path.Combine(Application.StartupPath, AppSetting.AppModulesPath);
                    if (!Directory.Exists(modulesPath))
                    {
                        Directory.CreateDirectory(modulesPath);
                    }
                    QuestionResult questionResult = QuestionResult.No;
                    foreach (string sourceFilePath in fd.FileNames)
                    {
                        string folderName = Path.GetFileNameWithoutExtension(sourceFilePath); // lấy tên thư mục = tên của dll
                        if (folderName.EndsWith(".dll", StringComparison.CurrentCultureIgnoreCase))
                        {
                            folderName = folderName.Remove(folderName.Length - 4);
                        }
                        string desFolderPath = Path.Combine(modulesPath, folderName);
                        if (!Directory.Exists(desFolderPath))
                        {
                            Directory.CreateDirectory(desFolderPath);
                        }
                        string fileName = Path.GetFileName(sourceFilePath);
                        string desFilePath = Path.Combine(desFolderPath, fileName);
                        try
                        {
                            if (!File.Exists(desFilePath))
                            {
                                File.Copy(sourceFilePath, desFilePath);
                            }
                            else
                            {
                                if (questionResult != QuestionResult.YesAll && questionResult != QuestionResult.NoAll)
                                {
                                    questionResult = CopyQuestion.Show(string.Format("File \"{0}\" already exist.\rDo you want to override?", fileName), "File already exist");
                                    if (questionResult == QuestionResult.Yes || questionResult == QuestionResult.YesAll)
                                    {
                                        CopyFile(sourceFilePath, desFilePath, true);
                                    }
                                }
                                else if (questionResult == QuestionResult.YesAll)
                                {
                                    CopyFile(sourceFilePath, desFilePath, true);
                                }
                            }
                            if (questionResult == QuestionResult.Cancel)
                            {
                                break;
                            }
                            else
                            {
                                if (desFilePath.EndsWith(".dll", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    PluggableManage.LoadAssembly(desFilePath);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            if (ex.Message.Contains("because it is being used by another process"))
                            {
                                MessageBox.Show(string.Format("Cannot override file \"{0}\" because it is being used by another process.", fileName), "Cannot override file", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                            }
                            else
                            {
                                throw ex;
                            }
                        }
                    }
                    LoadData();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            try
            {
                LoadData();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void btnConfig_Click(object sender, EventArgs e)
        {
            if (dgvModuleList.SelectedRows.Count > 0 )
            {
                IPluggableModule item = _ListOfModule[dgvModuleList.SelectedRows[0].Cells["DicKey"].Value.ToString()];
                if (item != null && !string.IsNullOrWhiteSpace(item.Name))
                {
                    FrmRouterConfig frm = new FrmRouterConfig(item);
                    if (frm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        foreach (var pi in item.GetType().GetProperties().Where(p => p.CanRead && p.CanWrite))
                        {
                            pi.SetValue(item, pi.GetValue(frm.outModule, null), null);
                        }
                    }
                }
            }
        }

        private void btnStartStop_Click(object sender, EventArgs e)
        {
            try
            {
                DialogResult drs = DialogResult.Yes;
                string processStatus = "";
                if (btnStartStop.Text == ButtonAction.Start) processStatus = "Starting...";
                else
                {
                    processStatus = "Stopping...";
                    drs = MessageBox.Show("Are you sure want to stop?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                }
                if (drs == DialogResult.Yes)
                {
                    FrmProgressBar.Show(processStatus);
                    if (dgvModuleList.SelectedRows.Count > 0)
                    {
                        foreach (DataGridViewRow row in dgvModuleList.SelectedRows)
                        {
                            StartStopModule(row);
                        }
                        SetBtnStartStopText(dgvModuleList.SelectedRows[0]);
                    }
                    else if (dgvModuleList.RowCount > 0)
                    {
                        StartStopModule(dgvModuleList.Rows[0]);
                        SetBtnStartStopText(dgvModuleList.Rows[0]);
                    }
                    SetParentControl();
                    FrmProgressBar.Hide();
                }
            }
            catch (Exception ex)
            {
                FrmProgressBar.Hide();
                MessageBox.Show(ex.ToString());
            }
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            try
            {
                if (dgvModuleList.SelectedRows.Count > 0)
                {
                    if (MessageBox.Show("Are you sure want to delete?", "Delete?", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.Yes)
                    {
                        FrmProgressBar.Show("Deleting...");
                        foreach (DataGridViewRow row in dgvModuleList.SelectedRows)
                        {
                            IPluggableModule item = _ListOfModule[row.Cells["DicKey"].Value.ToString()];
                            if (item != null)
                            {
                                if (!item.Running)
                                {
                                    string[] s = dgvModuleList.SelectedRows[0].Cells["DicKey"].Value.ToString().Split('|');
                                    if (s.Length > 0)
                                    {
                                        string fileName = s[0];
                                        string filePath = item.GetAssemblyLocation(); //Utils.Common.GetFilePath(fileName, AppSetting.AppModulesPath);
                                        if (!string.IsNullOrWhiteSpace(filePath))
                                        {
                                            if (PluggableManage.UnloadAssemblyOfStoppedModule(filePath))
                                            {
                                                File.Delete(filePath);
                                                // Xóa file config:
                                                string configFilePath = filePath + ".config";
                                                if (File.Exists(configFilePath))
                                                {
                                                    File.Delete(configFilePath);
                                                }
                                                //-----
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                FrmProgressBar.Hide();
                                MessageBox.Show("Module '" + item.Name + "' is running. You can not delete it.", "Delete file", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                            }
                        }
                        LoadData();
                        FrmProgressBar.Hide();
                    }
                }
            }
            catch (Exception ex)
            {
                FrmProgressBar.Hide();
                MessageBox.Show(ex.ToString());
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}